package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CategoryBasicDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.QuestionFormDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.QuestionAdminPageQuery;
import com.tianji.learning.domain.query.QuestionPageQuery;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.enums.QuestionStatus;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.service.IInteractionReplyService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author mxl
 * @since 2024-06-26
 */
@Service
@RequiredArgsConstructor
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {

    private final IInteractionReplyService iInteractionReplyService;

    private final UserClient userClient;

    private final SearchClient searchClient;

    private final CourseClient courseClient;

    private final CatalogueClient catalogueClient;

    private final CategoryCache categoryCache;

    @Override
    public void saveQuestion(QuestionFormDTO dto) {
        // 1. 获取当前用户ID
        Long user = UserContext.getUser();

        // 2.装PO
        InteractionQuestion interactionQuestion = BeanUtils.copyBean(dto, InteractionQuestion.class);
        interactionQuestion.setUserId(user);

        // 3. 保存
        this.save(interactionQuestion);
    }

    @Override
    public void updateQuestion(QuestionFormDTO dto, Long questionId) {
        // 1. 校验
        if(StringUtils.isBlank(dto.getTitle()) || (StringUtils.isBlank(dto.getDescription())) || (dto.getAnonymity() == null)){
            throw new BadRequestException("非法参数");
        }
        // 2. 校验id
        InteractionQuestion question = this.getById(questionId);
        if(question == null){
            throw new BadRequestException("问题不存在");
        }
        // 3. 权限校验。只能修改自己的

        Long user = UserContext.getUser();
        if(!user.equals(question.getUserId())){
            throw new BadRequestException("不能修改别人的问题");
        }


        // 4. dto转po
        question.setTitle(dto.getTitle());
        question.setAnonymity(dto.getAnonymity());
        question.setDescription(dto.getDescription());
        this.updateById(question);
    }

    @Override
    public PageDTO<QuestionVO> queryQuestionPage(QuestionPageQuery pageQuery) {
        // 1. 校验
        if(pageQuery.getCourseId() == null){
            throw new BadRequestException("课程ID为空");
        }
        // 2. 获取登录用户id
        Long user = UserContext.getUser();
        // 3. 分页查询互动问题表  onlyMe为treu加userId, 小节id不为空 按小节查   管理员下架的不返回
        Page<InteractionQuestion> questionPage = this.lambdaQuery()
                .select(InteractionQuestion.class, new Predicate<TableFieldInfo>() {
                    @Override
                    public boolean test(TableFieldInfo tableFieldInfo) {    // 判断列是否返回
                        return !tableFieldInfo.getProperty().equals("description");
                    }
                })
                .eq(pageQuery.getOnlyMine(), InteractionQuestion::getUserId, user)
                .eq(InteractionQuestion::getCourseId, pageQuery.getCourseId())
                .eq(pageQuery.getSectionId() != null, InteractionQuestion::getSectionId, pageQuery.getSectionId())
                .eq(InteractionQuestion::getHidden, false)
                .page(pageQuery.toMpPage("create_time", false));

        if(CollUtils.isEmpty(questionPage.getRecords())){
            return PageDTO.empty(pageQuery.toMpPage());
        }

        // 4. 根据最新回答id查询对应的回答信息  批量查询回答信息
        List<InteractionQuestion> records = questionPage.getRecords();
        // 获取用户id为第5步做准备 （问题）
        List<Long> userIds = records.stream().filter(record -> !record.getAnonymity()).map(InteractionQuestion::getUserId).collect(Collectors.toList());
        // 获取回答Id
        List<Long> lastedAnswer = records.stream().filter(record -> record.getLatestAnswerId() != null)
                .map(InteractionQuestion::getLatestAnswerId).collect(Collectors.toList());
        Map<Long, InteractionReply> replyMap = new HashMap<>();
        if(!CollUtils.isEmpty(lastedAnswer)){
            List<InteractionReply> interactionReplies = iInteractionReplyService.list(Wrappers.<InteractionReply>lambdaQuery()
                    .in(InteractionReply::getId, lastedAnswer)
                    .eq(InteractionReply::getHidden, false));

            for (InteractionReply interactionReply : interactionReplies) {
                replyMap.put(interactionReply.getId(), interactionReply);

                // 获取用户id为第5步做准备 （回答）
                if(!interactionReply.getAnonymity()){
                    userIds.add(interactionReply.getUserId());
                }
            }

            replyMap = interactionReplies.stream().collect(Collectors.toMap(InteractionReply::getId, reply -> reply));
        }
        // 5. 远程调用用户服务 批量获取用户信息
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userMap = userDTOS.stream()
                .collect(Collectors.toMap(UserDTO::getId, userD->userD));

        // 4. 封装Vo
        List<QuestionVO> voList = new ArrayList<>();
        for (InteractionQuestion record : records) {
            QuestionVO questionVO = BeanUtils.copyBean(record, QuestionVO.class);
            // 1. 封装用户信息
            if(!record.getAnonymity()){
                UserDTO userDto = userMap.get(record.getUserId());
                if(userDto != null){
                    questionVO.setUserName(userDto.getName());
                    questionVO.setUserIcon(userDto.getIcon());
                }
            }
            // 2. 封装最近回答信息
            if(record.getLatestAnswerId() != null){
                InteractionReply reply = replyMap.get(record.getLatestAnswerId());
                questionVO.setLatestReplyContent(reply.getContent());
                if(!reply.getAnonymity()){
                    UserDTO userDto = userMap.get(reply.getUserId());
                    if(userDto != null){
                        questionVO.setLatestReplyUser(userDto.getName());
                    }
                }
            }
            voList.add(questionVO);
        }
        return PageDTO.of(questionPage, voList);
    }

    @Override
    public QuestionVO queryQuestionById(Long id) {
        // 1. 校验
        if(id == null){
            throw new BadRequestException("请求参数错误");
        }

        // 2. 查询互动问题表
        InteractionQuestion question = this.getById(id);
        if(question == null){
            throw new BadRequestException("问题不存在");
        }
        // 3. 如果改问题隐藏 返回空
        if(question.getHidden()){
            return null;
        }
        QuestionVO questionVO = BeanUtils.copyBean(question, QuestionVO.class);
        // 4. 匿名提问要屏蔽名字和头像
        if(!question.getAnonymity()){
            UserDTO userDTO = userClient.queryUserById(question.getUserId());
            if(userDTO != null){
                questionVO.setUserName(userDTO.getName());
                questionVO.setUserIcon(userDTO.getIcon());
            }
        }
        return questionVO;
    }

    @Override
    public PageDTO<QuestionAdminVO> queryQuestionAdminVOPage(QuestionAdminPageQuery query) {
        // 0. 根据课程名进行模糊查询
        String couseName = query.getCourseName();
        List<Long> cids = null;
        if(!StringUtils.isBlank(couseName)){
            cids = searchClient.queryCoursesIdByName(couseName);
            if (CollUtils.isEmpty(cids)){
                return PageDTO.empty(0L, 0L);
            }
        }
        // 1. 查询互动问题表 条件 前端传条件 分页查询 排序按照提问时间倒叙
        Page<InteractionQuestion> questionPage = this.lambdaQuery()
                .in(cids != null, InteractionQuestion::getChapterId, cids)
                .eq(query.getStatus() != null, InteractionQuestion::getStatus, query.getStatus())
                .gt(query.getBeginTime()!=null, InteractionQuestion::getCreateTime, query.getBeginTime())
                .lt(query.getEndTime()!=null, InteractionQuestion::getCreateTime, query.getEndTime())
                .page(query.toMpPageDefaultSortByCreateTimeDesc());

        List<InteractionQuestion> records = questionPage.getRecords();
        if(CollUtils.isEmpty(records)){
            return PageDTO.empty(0L, 0L);
        }
        Set<Long> uIds = new HashSet<>();
        Set<Long> courseIds = new HashSet<>();
        Set<Long> chapterAndSectionIds = new HashSet<>();

        for (InteractionQuestion record : records) {
            uIds.add(record.getUserId());
            courseIds.add(record.getCourseId());
            chapterAndSectionIds.add(record.getChapterId());
            chapterAndSectionIds.add(record.getSectionId());
        }
        // 2. 远程调用用户服务 获取用户信息
        List<UserDTO> userDTOS = userClient.queryUserByIds(uIds);
        if(CollUtils.isEmpty(userDTOS)){
            throw new BizIllegalException("用户不存在");
        }
        Map<Long, UserDTO> userMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, u -> u));
        // 3. 远程调用课程服务 获取课程信息
        List<CourseSimpleInfoDTO> courses = courseClient.getSimpleInfoList(courseIds);

        if(CollUtils.isEmpty(courses)){
            throw new BizIllegalException("课程不存在");
        }
        Map<Long, CourseSimpleInfoDTO> courseMap = courses.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));

        // 4. 远程调用课程服务 获取章节信息
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(chapterAndSectionIds);
        if(CollUtils.isEmpty(cataSimpleInfoDTOS)){
            throw new BizIllegalException("章节不存在");
        }
        Map<Long, String> cataNameMap = cataSimpleInfoDTOS.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, cata -> cata.getName()));

        // 5.po 转 vo
        List<QuestionAdminVO> voList = new ArrayList<>();
        for (InteractionQuestion record : records) {
            QuestionAdminVO adminVO = BeanUtils.copyBean(record, QuestionAdminVO.class);
            UserDTO userDTO = userMap.get(record.getUserId());
            if(userDTO != null){
                adminVO.setUserName(userDTO.getName());
            }
            CourseSimpleInfoDTO courseSimpleInfoDTO = courseMap.get(record.getCourseId());
            if(courseSimpleInfoDTO != null){
                adminVO.setCourseName(courseSimpleInfoDTO.getName());
                // 5.1 获取课程的分类id列表， 从缓存中查询
                // 获取1 2 3 级分类
                List<Long> categoryIds = courseSimpleInfoDTO.getCategoryIds();
                String categoryName = categoryCache.getCategoryNames(categoryIds);
                adminVO.setCategoryName(categoryName); // 拼接字段
            }
            String chapterName = cataNameMap.get(record.getChapterId());
            if(chapterName != null){
                adminVO.setChapterName(chapterName);
            }
            String sectionName = cataNameMap.get(record.getSectionId());
            if(sectionName != null){
                adminVO.setSectionName(sectionName);
            }

            voList.add(adminVO);
        }

        return PageDTO.of(questionPage, voList);
    }

    @Override
    public void updateQuestionHiddenState(Long id, Boolean hidden) {
        // 1.参数校验
        if(id == null || hidden == null){
            throw new BadRequestException("参数不能为空");
        }

        InteractionQuestion question = this.getById(id);

        if(question != null){
            throw new BadRequestException("该问题不存在");
        }

        this.update(Wrappers.<InteractionQuestion>lambdaUpdate()
                .eq(InteractionQuestion::getId, id)
                .set(InteractionQuestion::getHidden, hidden));
    }

    @Override
    public QuestionAdminVO queryQuestionAdminVoDetails(Long id) {
        // 1. 参数校验
        if(id == null){
            throw new BadRequestException("问题不能为空");
        }
        // 2. 查询问题
        InteractionQuestion question = this.getById(id);

        // 2.1 状态转换
        if(question.getStatus() == QuestionStatus.UN_CHECK){
            question.setStatus(QuestionStatus.CHECKED);
            this.updateById(question);
        }

        // 4.远程调用课程服务
        // 4.1 获取课程名
        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(question.getCourseId(), false, true);
        if(courseInfo == null){
            throw new BizIllegalException("课程不存在");
        }
        // 4.2 获取小节
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(List.of(question.getChapterId(), question.getSectionId()));
        if(CollUtils.isEmpty(cataSimpleInfoDTOS)){
            throw new BizIllegalException("小节不存在");
        }
        Map<Long, String> catalogName = cataSimpleInfoDTOS.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, cataSimpleInfoDTO -> cataSimpleInfoDTO.getName()));
        // 5. 查询本地缓存获取三级分类
        String categorys = categoryCache.getCategoryNames(List.of(courseInfo.getFirstCateId(), courseInfo.getSecondCateId(), courseInfo.getThirdCateId()));
        if(StringUtils.isBlank(categorys)){
            throw new BizIllegalException("分类不存在");
        }
        // 3. 远程调用用户服务 调用远程服务获取负责老师 和 用户的信息
        List<Long> teacherIds = courseInfo.getTeacherIds();
        teacherIds.add(question.getUserId());
        List<UserDTO> userDTOS = userClient.queryUserByIds(teacherIds);
        if(CollUtils.isEmpty(userDTOS)){
            throw new BizIllegalException("用户不存在");
        }
        Map<Long, String> users = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, u -> u.getUsername()));
        // 7.po转vo
        QuestionAdminVO adminVO = BeanUtils.copyBean(question, QuestionAdminVO.class);
        adminVO.setUserName(users.getOrDefault(question.getUserId(), null));
        adminVO.setCourseName(courseInfo.getName());
        adminVO.setChapterName(catalogName.getOrDefault(question.getChapterId(), null));
        adminVO.setSectionName(catalogName.getOrDefault(question.getSectionId(), null));
        adminVO.setCategoryName(categorys);
        List<String> teacherNames = userDTOS.stream().filter(u -> u.getId() != question.getUserId()).map(UserDTO::getName).collect(Collectors.toList());
        StringBuilder teahcerName = new StringBuilder();
        for (String teacher : teacherNames) {
            teahcerName.append(teacher);
            teahcerName.append(' ');
        }
        adminVO.setTeacherName(teahcerName.deleteCharAt(teahcerName.length()-1).toString());

        return adminVO;
    }
}
